#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <paths.h>
#include <openssl/sha.h>
#include <ctype.h>
#include <sys/utsname.h>
#include <stdbool.h>
#include <syslog.h>
#include <sys/types.h>
#include <unistd.h>

#include "kylin-verify.h"
#include "encrypt.h"
#include "dict.h"
#include "date.h"
#include "misc.h"
#include "hwid.h"
#include "kylin-activation.h"
#include "kylin-ukey.h"
#include "text-i18n.h"

/* NOT_ACTIVATED and ACTIVATED are only used in activate_status*/
#define NOT_ACTIVATED 0
#define ACTIVATED 1

#define NOT_ON_TRIAL 0
#define ON_TRIAL 1

#if defined __x86_64 || defined __x86_64__ || defined __amd64 || defined __amd64__
#define PLATFORM_STRING "x86_64"
#endif

#if defined __i386 || defined __i386__ || defined __i686 || defined __i686__
#define PLATFORM_STRING "i386"
#endif

#ifdef __aarch64__
#define PLATFORM_STRING "arm64"
#endif

#ifdef __arm__
  #ifndef __LP64__
    #define PLATFORM_STRING "armhf"
  #endif
#endif

#ifdef __mips__
  #ifdef __LP64__
    #define PLATFORM_STRING "mips64el"
  #else
    #define PLATFORM_STRING "mipsel"
  #endif
#endif

#ifdef __sw_64__
#define PLATFORM_STRING "sw64"
#endif

#ifdef __loongarch64 
#define PLATFORM_STRING "loongarch64"
#endif 
#define KYLIN_INFORMATION_FILE "/etc/.kyinfo"
#define KYLIN_ACTIVATION_FILE "/etc/.kyactivation"
#define KYLIN_LICENSE_FILE "/etc/LICENSE"

#define LOG_FILE "/var/log/kylin-activation-check"

#define RESULT_INTERFACE "/sys/kylin_authentication/result"

#define OSINFO_PATH "/proc/osinfo"

#define BUF_SIZE 1024
#define OUT_BUF_SIZE 4096
#define DATE_STRING_LENGTH 64

extern char* escape_get_expire_date();
extern char* escape_license_serial();
extern int license_should_escape();

extern char *strcasestr(const char *haystack, const char *needle);

/*
 * kylin_activation_contact, contact to file to read and write verify message
 */
static void kylin_activation_contact(const char* read_file, const char* write_file);

/*
 * kylin_activation_verify_contact, contact to kernel to tell if system verification status
 */
static void kylin_activation_verify_contact();

#ifdef CHECK_ENV
/*
 * kylin_activation_env_contact, contact to kernel to tell if system environment  status
 */
static void kylin_activation_env_contact();
#endif

/*
 * i18n_initial, initialize i18n
 */
static void i18n_initial();

static char* license_file = NULL;
static char* info_file = NULL;
static char* activate_file = NULL;

enum
{
	NO_ACTIVATED_CODE = -1,
	NORMALLY_ACTIVATED = 0,
	WITH_UKEY_ACTIVATED = 1
}activate_status;

static int activation_status = NO_ACTIVATED_CODE;
static uid_t uid = 0;
/*
 * _serial_validation_check, check if serial number is valid.
 * A serial number string is made up of digital character, and valid length is LEGACY_SERIAL_LEN or not less than NEW_SERIAL_LEN.
 * return true if serial number is valid, or return false;
 */
static bool _serial_validation_check(const char *serial)
{
	const char* p = serial;
	int len = 0;

	if (!serial || strlen(serial) == 0)
		return false;

	while (*p != '\0')
	{
		if(!isdigit(*p))
		{
			return false;
		}
		++p;
	}

	len = strlen(serial);

	if (len == LEGACY_SERIAL_LEN || len == BATCH_SERIAL_LEN || len >= NEW_SERIAL_LEN)
	{
		return true;
	}

	return false;
}


/*
 * string_valid, check if a string is valid.
 * return true if a string is not NULL and not empty, or return false.
 */
static inline bool string_valid(const char* str)
{
	if (!str)
		return false;

	return strlen(str) > 0 ? true : false;
}

/*
 * string_address, get string address.
 * return string address if string is not NULL and not empty, or return NULL.
 */
static inline char* string_address(char* str)
{
	if (!str)
		return NULL;

	return strlen(str) > 0 ? str : NULL;
}

enum
{
	INFO_TYPE_UNKNOWN = 0,
	INFO_TYPE_LEGACY,
	INFO_TYPE_NEW
} info_type;

struct activation_info
{
	int type;
	char license_serial[32];
	char real_serial[32];
	char license_trial[32];
	char license_to[256];
	char license_platform[32];
	char kyinfo_to[256];
	char activate_file_date[DATE_STRING_LENGTH];
	char kyinfo_term[DATE_STRING_LENGTH];
	char old_expire_date[DATE_STRING_LENGTH];
	char kyinfo_ukey[64];
#ifdef __aarch64__
	char license_class[32];
#endif
};

static struct activation_info info = 
{
	.type = INFO_TYPE_UNKNOWN,
	.license_serial = {0},
	.real_serial = {0},
	.license_trial = {0},
	.license_to = {0},
	.license_platform = {0},
	.kyinfo_to = {0},
	.activate_file_date = {0},
	.kyinfo_term = {0},
	.old_expire_date = {0},
	.kyinfo_ukey = {0},
#ifdef __aarch64__
	.license_class = {0},
#endif
};

#ifdef CHECK_ENV
/*
 * kylin_env_check, check kylin environment
 * return NO_ERROR if ok, or error number if not
 */
extern int kylin_env_check(char* buffer);
char env_check_wrong[BUF_SIZE];
char env_check_error[BUF_SIZE];
#endif

/*
 * serial_number_match_check, check if serial_no matches rules of given license_serial.
 * license_serial: serial from license file.
 * serial_no: custom serial
 */
static int serial_number_match_check(const char* license_serial, const char* serial_no)
{
	int license_serial_mode = SERIAL_MODE_UNKNOWN;
	int serial_mode = SERIAL_MODE_UNKNOWN;

	if(!license_serial || !serial_no)
	{
		return NO_SERIAL_NUMBER_ERROR;
	}

	if(!_serial_validation_check(serial_no))
	{
		return SERIAL_NUMBER_VALIDATION_ERROR;
	}

	// check serial_no first
	serial_mode = _serial_number_mode(serial_no);
	// if((SERIAL_MODE_UNKNOWN == serial_mode) || (SERIAL_MODE_BATCH == serial_mode))
	if(SERIAL_MODE_UNKNOWN == serial_mode)
	{
		return SERIAL_NUMBER_VALIDATION_ERROR;
	}
	if(SERIAL_MODE_LEGACY == serial_mode)
	{
		if(strcmp(license_serial, serial_no) != 0)
		{
			return ACTIVATION_SERIAL_NUMBER_MATCH_ERROR;
		}
	}

	// check match
	license_serial_mode = _serial_number_mode(license_serial);
	if((SERIAL_MODE_LEGACY == license_serial_mode) || (SERIAL_MODE_NEW == license_serial_mode))
	{
		if(strcmp(license_serial, serial_no) != 0)
		{
			return ACTIVATION_SERIAL_NUMBER_MATCH_ERROR;
		}
	} else if(SERIAL_MODE_BATCH == license_serial_mode) {
		if(!_product_type_check(license_serial, serial_no))
		{
			return PRODUCT_TYPE_MATCH_ERROR;
		}
	} else {
		return LICENSE_SERIAL_NUMBER_VALIDATION_ERROR;
	}

	return NO_ERROR;
}

/*
 * _kylin_activation_activate_status, check if system is activated
 * return 1 if system is under activated status, or 0 if not
 */
static int _kylin_activation_activate_status(const char* serial, int* result, int log);

/*
 * _kylin_activation_activate_system_real, activate system really , not just test
 * return NO_ERROR if succeed, or error number if not
 */
static int _kylin_activation_activate_system_real(const char* activation_code_with_hyphen, const char* ukey_hid, const char* serial, int prompt, int test);

/*
 * i18n_initial, initialize i18n
 */
static void i18n_initial()
{
	static int has_been_initialized = 0;

	if(has_been_initialized)
		return;

	setlocale(LC_MESSAGES, "");
	bindtextdomain (PACKAGE, LOCALEDIR);
	textdomain(PACKAGE);
	bind_textdomain_codeset(PACKAGE, "utf8");

	has_been_initialized = 1;
}

/*
 * redirect_stdio, redirect stdin, stdout, stderr to /dev/null if they don't exist
 */
void redirect_stdio()
{
	int fd;
	struct stat sb, tmp;

	if((fd = open(_PATH_DEVNULL, O_RDWR)) != -1)
	{
		if((fstat(fd, &sb) == 0) && S_ISCHR(sb.st_mode))
		{
			if(fstat(STDIN_FILENO, &tmp) != 0)
				dup2(fd, STDIN_FILENO);
			if(fstat(STDOUT_FILENO, &tmp) != 0)
				dup2(fd, STDOUT_FILENO);
			if(fstat(STDERR_FILENO, &tmp) != 0)
				dup2(fd, STDERR_FILENO);

			if(fd > 2)
				close(fd);
		}
		else
			close(fd);
	}
}

/*
 * kylin_activation_kyinfo_set_value, set key=value in group into key file
 */
static void kylin_activation_kyinfo_set_value(const char* file, const char* group, const char* key, const char* value)
{
	GKeyFile *key_file = NULL;

	if (!file || !group || !key || !value)
		return;

	key_file = key_file_load_from_file(file);
	if (key_file)
	{
		key_file_set_value(key_file, group, key, value);
		key_file_save_to_file(key_file, file);
		g_key_file_free(key_file);
	}
}

/*
char* kylin_activation_get_trial_date()
{
	return license_trial;
}
*/

/*
 * kylin_activation_get_expire_date, get expire date string
 */
char* kylin_activation_get_expire_date(int* result);

/*
 * kylin_activation_get_result_message, get result message according to result number
 */
char* kylin_activation_get_result_message(int result)
{

	i18n_initial();

	switch(result)
	{
		case(LICENSE_VERIFY_ERROR) :
		case(LICENSE_LOAD_ERROR) :
		case(SIGSUM_RED_ERROR) :
		case(BAD_SIGNATURE_ERROR) :
		case(SIGNATURE_STATUS_ERROR) :
		case(LICENSE_NO_SIGNATURE) :
			return _("Failed to verify LICENSE file");
			//return "LICENSE文件验证有问题";
		case(LICENSE_DATA_FORMAT_ERROR) :
			return _("There is something wrong with content of LICENSE file");
			//return "LICENSE文件内容格式错误";
		case(LICENSE_SERIAL_ERROR) :
			return _("There is no serial number in LICENSE file");
			//return "LICENSE文件没有序列号";
		case(KYINFO_ERROR) :
			return _("There is no valid kylin information file");
			//return "无有效的麒麟信息文件";
		case(REGISTER_CREATION_ERROR) :
			return _("Failed to generate registration code");
			//return "注册码生成失败";
		case(REGISTER_DEAL_HYPHEN_ERROR) :
			return _("Failed to deal with registration code");
			//return "注册码处理失败";
		case(QRCODE_CREATION_ERROR) :
			return _("Fail to generate QR code string");
			//return "二维码字符串生成失败";
		case(ACT_CODE_DEAL_HYPHEN_ERROR) :
			return _("Failed to deal with activation code");
			//return "激活码处理失败";
		case(INVALID_ACT_CODE) :
			return _("Invalid activation code");
			//return "无效的激活码";
		case(ACT_CODE_HAS_EXPIRED) :
			return _("This activation contains a expired date");
			//return "此激活码所含使用时间已到期";
		case(ACT_EXPIRE_EARLIER_THAN_TRIAL) :
			return _("This activation's expiration date is earlier than expiration date for trial");
			//return "激活码所包含到期时间早于试用到期时间";
		case(ACT_EXPIRE_EARLIER_THAN_ORIGINAL) :
			return _("System has already got a longer activation period");
			//return "系统已含有有效期更长的激活码";
		case(ACT_CODE_SAVE_ERROR) :
			return _("Fail to save activation code");
			//return "激活码保存失败";
		case(NO_VALID_PUBLIC_KEY) :
			return _("There is no valid public key");
			//return "无有效的公钥";
		case(SYSTEM_TIME_ERROR) :
			return _("There is something wrong with system time");
			//return "系统时间有问题";
		case(GPGME_INITIALIZATION_ERROR) :
			return _("Failed to initialize gpgme");
			//return "gpgme初始化失败";
		case(HARDWARE_INFORMATION_ERROR) :
			return _("Failed to get hardware information");
			//return "无法获取硬件信息";
		case (SYSTEM_VERSION_INFORMATION_MATCH_ERROR):
			return _("system version information does not match");
			//return "系统版本信息不匹配"
		case (LICENSE_DETECTION_FAIL) :
			return _("LICENSE detection fail");
			//return "LICENSE检测失败"
#ifdef __aarch64__
		case(LICENSE_NO_CLASS_ERROR) :
			return _("There is no classification for this system in LICENSE file");
			//return "LICENSE文件无版本类型";
		case(LICENSE_CLASS_MATCH_ERROR) :
			return _("Classification for this system dismatches");
			//return "版本类型不匹配";
#endif
		case(NO_UKEY_FOUND) :
			return _("No UKey is inserted");
			//return "没有插入UKEY";
		case(UKEY_LOGIN_ERROR) :
			return _("UKey fails to login");
			//return "UKEY登录失败";
		case(UKEY_GET_DATA_ERROR) :
			return _("Failed to get data from UKey");
			//return "UKEY数据获取失败";
		case(UKEY_GET_HID_ERROR) :
			return _("Failed to get hardware ID of UKey");
			//return "UKEY硬件ID获取失败";
		case(UKEY_KEY_FILE_ERROR) :
			return _("Wrong format for UKey data");
			//return "UKEY数据格式错误";
		case(UKEY_NO_SERIAL) :
			return _("There is no serial number in UKey");
			//return "UKEY未包含服务序列号";
		case(UKEY_NO_EXPIRE_TIME) :
			return _("UKey doesn't contain a valid expiration date");
			//return "UKEY未包含有效激活期限";
		case(UKEY_MODULE_COUNT_ERROR) :
			return _("Failed to get counter number of UKey");
			//return "未成功获取UKEY计数次数";
		case(UKEY_MODULE_CHECK_ERROR) :
			return _("Failed to get counter status of UKey");
			//return "未成功获取UKEY计数状态";
		case(UKEY_MODULE_DECREASE_ERROR) :
			return _("Failed to decrease counter of UKey");
			//return "未成功减少UKEY计数";
		case(UKEY_MODULE_NO_MORE_COUNT) :
			return _("Counter of UKey has been used up");
			//return "UKEY可激活数已经达到上限";
		case(UKEY_SPACE_FULL) :
			return _("UKey's space is full, so it cannot activate another unactivated system");
			//return "UKEY空间已满，无法再激活新的机器";
		case(UKEY_MODULE_IS_ZERO) :
			return _("Counter of UKey has been used up");
			//return "UKEY可激活数已经达到上限";
		case(UKEY_MODULE_CANNOT_REDUCE) :
			return _("Counter of UKey cannot be decreased");
			//return "UKEY不能成功计数";
		case(UKEY_WRITE_DATA_ERROR) :
			return _("Failed to write data to UKey");
			//return "UKEY未能成功写数据";
		case(INVALID_REGISTER_CODE) :
			return _("Invalid registration code");
			//return "无效的注册码";
		case(UKEY_LOGOFF_ERROR) :
			return _("UKey fails to logout");
			//return "UKEY未能成功登出";
		case(UKEY_LIBRARY_LOAD_ERROR) :
			return _("Failed to initialize UKey");
			//return "UKEY初始化失败";
		case(SERIAL_NUMBER_MATCH_ERROR) :
			return _("The UKey dismatches with LICENSE file");
			//return "LICENSE的服务序列号与UKEY所含服务序列号不符";
		case(UKEY_EXPIRE_DEAL_HYPHEN_ERROR) :
			return _("Failed to deal with expiration date in UKey");
			//return "UKEY激活到期时间处理失败";
		case(UKEY_ACTIVATE_SYSTEM_FAILED) :
			return _("Failed to activate system via UKey");
			//return "UKEY激活系统失败";
		case(HAS_NORMALLY_ACTIVATED) :
			return _("System has already been activated, There is no need to activate it again");
			//return "系统已经激活，无须重复激活";
		case(HAS_ACTIVATED_WITH_ANOTHER_UKEY) :
			return _("System has already been activated by another UKey, There is no need to activate it again");
			//return "系统已经由其他UKEY激活过，无须重复激活";
		case(UKEY_INIT_ERROR) :
			return _("Failed to initialize UKey environment");
			//return "UKEY环境初始化异常\n";
		case(UKEY_CONTENT_ERROR) :
			return _("Failed to get information of UKey");
		case(GPGME_ENCRYPT_ERROR) :
			return _("Failed to encrypt UKey's information");
		case(INVALID_SIGNATURE) :
			return _("Invalid signature");
#ifdef CHECK_ENV
		case(NON_KYLIN_PACKAGE) :
			if(strlen(env_check_wrong) > 0)
			{
				memset(env_check_error, 0, BUF_SIZE);
				sprintf(env_check_error, _("Kylin provided package is modified: %s"), env_check_wrong);
				return env_check_error;
			}
			else
			{
				return _("Kylin provided package is modified");
			}
		case(MODIFIED_FILE_ERROR) :
			if(strlen(env_check_wrong) > 0)
			{
				memset(env_check_error, 0, BUF_SIZE);
				sprintf(env_check_error, _("Kylin provided file is modified: %s"), env_check_wrong);
				return env_check_error;
			}
			else
			{
				return _("Kylin provided file is modified");
			}
#endif
		case(SERIAL_NUMBER_VALIDATION_ERROR) :
			return _("Invalid serial number");
		case(NO_SERIAL_NUMBER_ERROR) :
			return _("There is no valid serial number");
		case(INVALID_OVERWRITE_SERIAL_NUMBER_ERROR) :
			return _("Cannot overwrite original serial number");
		case(LICENSE_SERIAL_NUMBER_VALIDATION_ERROR) :
			return _("License serial number is invalid");
		case(UKEY_SERIAL_NUMBER_VALIDATION_ERROR) :
			return _("Ukey license serial number is invalid");
		case(PRODUCT_TYPE_MATCH_ERROR) :
			return _("Product type doesn't match");
		case(LICENSE_NO_PLATFORM_ERROR) :
			return _("License file doesn't contain platform information");
		case(LICENSE_PLATFORM_MATCH_ERROR) :
			return _("Platform doesn't match");
		case(PRODUCE_NUMBER_MATCH_ERROR) :
			return _("Produce number doesn't match");
		case(ACTIVATION_SERIAL_NUMBER_MATCH_ERROR) :
			return _("The serial number dismatches with LICENSE file");
		case(NO_ERROR) :
			return NULL;
		default :
			return _("Other error");
			//return "其他错误";
	}
	return NULL;
}

/*
 * kylin_activation_print_result_message, print message according to result number
 */
void kylin_activation_print_result_message(int result)
{
	i18n_initial();

	switch(result)
	{
		case(LICENSE_VERIFY_ERROR) :
		case(LICENSE_LOAD_ERROR) :
		case(SIGSUM_RED_ERROR) :
		case(BAD_SIGNATURE_ERROR) :
		case(SIGNATURE_STATUS_ERROR) :
		case(LICENSE_NO_SIGNATURE) :
			fprintf(stderr, _("Failed to verify LICENSE file.\n"));
			//fprintf(stderr, "LICENSE文件验证有问题\n");
			break;
		case(LICENSE_DATA_FORMAT_ERROR) :
			fprintf(stderr, _("There is something wrong with content of LICENSE file.\n"));
			//fprintf(stderr, "LICENSE文件内容格式错误\n");
			break;
		case(LICENSE_SERIAL_ERROR) :
			fprintf(stderr, _("There is no serial number in LICENSE file.\n"));
			//fprintf(stderr, "LICENSE文件没有序列号\n");
			break;
		case(KYINFO_ERROR) :
			fprintf(stderr, _("There is no valid kylin information file.\n"));
			//fprintf(stderr, "无有效的麒麟信息文件\n");
			break;
		case(REGISTER_CREATION_ERROR) :
			fprintf(stderr, _("Failed to generate registration code\n"));
			//fprintf(stderr, "注册码生成失败\n");
			break;
		case(REGISTER_DEAL_HYPHEN_ERROR) :
			fprintf(stderr, _("Failed to deal with registration code.\n"));
			//fprintf(stderr, "注册码处理失败\n");
			break;
		case(QRCODE_CREATION_ERROR) :
			fprintf(stderr, _("Fail to generate QR code string.\n"));
			//fprintf(stderr, "二维码字符串生成失败\n");
			break;
		case(ACT_CODE_DEAL_HYPHEN_ERROR) :
			fprintf(stderr, _("Failed to deal with activation code.\n"));
			//fprintf(stderr, "激活码处理失败\n");
			break;
		case(INVALID_ACT_CODE) :
			fprintf(stderr, _("Invalid activation code.\n"));
			//fprintf(stderr, "无效的激活码\n");
			break;
		case(ACT_CODE_HAS_EXPIRED) :
			fprintf(stderr, _("This activation contains a expired date.\n"));
			//fprintf(stderr, "此激活码所含使用时间已到期\n");
			break;
		case(ACT_EXPIRE_EARLIER_THAN_TRIAL) :
			fprintf(stderr, _("This activation's expiration date is earlier than expiration date for trial.\n"));
			//fprintf(stderr, "激活码所包含到期时间早于试用到期时间\n");
			if(string_valid(info.license_trial))
				fprintf(stderr, _("Expiration date of trial: %s\n"), info.license_trial);
				//fprintf(stderr, "试用到期时间： %s\n", license_trial);
			break;
		case(ACT_EXPIRE_EARLIER_THAN_ORIGINAL) :
			fprintf(stderr, _("System has already got a longer activation period.\n"));
			//fprintf(stderr, "系统已含有有效期更长的激活码\n");
			if(string_valid(info.activate_file_date))
				fprintf(stderr, _("Expiration date: %s\n"), info.activate_file_date);
				//fprintf(stderr, "到期时间为： %s\n", activate_file_date);
			break;
		case(ACT_CODE_SAVE_ERROR) :
			fprintf(stderr, _("Fail to save activation code.\n"));
			//fprintf(stderr, "激活码保存失败\n");
			break;
		case(NO_VALID_PUBLIC_KEY) :
			fprintf(stderr, _("There is no valid public key.\n"));
			//fprintf(stderr, "无有效的公钥\n");
			break;
		case(SYSTEM_TIME_ERROR) :
			fprintf(stderr, _("There is something wrong with system time.\n"));
			//fprintf(stderr, "系统时间有问题\n");
			break;
		case(GPGME_INITIALIZATION_ERROR) :
			fprintf(stderr, _("Failed to initialize gpgme.\n"));
			//fprintf(stderr, "gpgme初始化失败\n");
			break;
		case(HARDWARE_INFORMATION_ERROR) :
			fprintf(stderr, _("Failed to get hardware information.\n"));
			//fprintf(stderr, "无法获取硬件信息\n");
			break;
		case (SYSTEM_VERSION_INFORMATION_MATCH_ERROR):
			fprintf(stderr, _("system version information does not match.\n"));
			//fprintf(stderr, "系统版本信息不匹配\n");
			break;
		case (LICENSE_DETECTION_FAIL):
			fprintf(stderr, _("LICENSE detection fail.\n"));
			//fprintf(stderr, "LICENSE检测失败\n");
			break;
#ifdef __aarch64__
		case(LICENSE_NO_CLASS_ERROR) :
			fprintf(stderr, _("There is no classification for this system in LICENSE file.\n"));
			//fprintf(stderr, "LICENSE文件无版本类型\n");
			break;
		case(LICENSE_CLASS_MATCH_ERROR) :
			fprintf(stderr, _("Classification for this system dismatches.\n"));
			//fprintf(stderr, "版本类型不匹配\n");
			break;
#endif
		case(NO_UKEY_FOUND) :
			fprintf(stderr, _("No UKey is inserted.\n"));
			//fprintf(stderr, "没有插入UKEY\n");
			break;
		case(UKEY_LOGIN_ERROR) :
			fprintf(stderr, _("UKey fails to login.\n"));
			//fprintf(stderr, "UKEY登录失败\n");
			break;
		case(UKEY_GET_DATA_ERROR) :
			fprintf(stderr, _("Failed to get data from UKey.\n"));
			//fprintf(stderr, "UKEY数据获取失败\n");
			break;
		case(UKEY_GET_HID_ERROR) :
			fprintf(stderr, _("Failed to get hardware ID of UKey.\n"));
			//fprintf(stderr, "UKEY硬件ID获取失败\n");
			break;
		case(UKEY_KEY_FILE_ERROR) :
			fprintf(stderr, _("Wrong format for UKey data.\n"));
			//fprintf(stderr, "UKEY数据格式错误\n");
			break;
		case(UKEY_NO_SERIAL) :
			fprintf(stderr, _("There is no serial number in UKey.\n"));
			//fprintf(stderr, "UKEY未包含服务序列号\n");
			break;
		case(UKEY_NO_EXPIRE_TIME) :
			fprintf(stderr, _("UKey doesn't contain a valid expiration date.\n"));
			//fprintf(stderr, "UKEY未包含有效激活期限\n");
			break;
		case(UKEY_MODULE_COUNT_ERROR) :
			fprintf(stderr, _("Failed to get counter number of UKey.\n"));
			//fprintf(stderr, "未成功获取UKEY计数次数\n");
			break;
		case(UKEY_MODULE_CHECK_ERROR) :
			fprintf(stderr, _("Failed to get counter status of UKey.\n"));
			//fprintf(stderr, "未成功获取UKEY计数状态\n");
			break;
		case(UKEY_MODULE_DECREASE_ERROR) :
			fprintf(stderr, _("Failed to decrease counter of UKey.\n"));
			//fprintf(stderr, "未成功减少UKEY计数\n");
			break;
		case(UKEY_MODULE_NO_MORE_COUNT) :
			fprintf(stderr, _("Counter of UKey has been used up.\n"));
			//fprintf(stderr, "UKEY可激活数已经达到上限\n");
			break;
		case(UKEY_SPACE_FULL) :
			fprintf(stderr, _("UKey's space is full, so it cannot activate another unactivated system.\n"));
			//fprintf(stderr, "UKEY空间已满，无法再激活新的机器\n");
			break;
		case(UKEY_MODULE_IS_ZERO) :
			fprintf(stderr, _("Counter of UKey has been used up.\n"));
			//fprintf(stderr, "UKEY可激活数已经达到上限\n");
			break;
		case(UKEY_MODULE_CANNOT_REDUCE) :
			fprintf(stderr, _("Counter of UKey cannot be decreased.\n"));
			//fprintf(stderr, "UKEY不能成功计数\n");
			break;
		case(UKEY_WRITE_DATA_ERROR) :
			fprintf(stderr, _("Failed to write data to UKey.\n"));
			//fprintf(stderr, "UKEY未能成功写数据\n");
			break;
		case(INVALID_REGISTER_CODE) :
			fprintf(stderr, _("Invalid registration code.\n"));
			//fprintf(stderr, "无效的注册码\n");
			break;
		case(UKEY_LOGOFF_ERROR) :
			fprintf(stderr, _("UKey fails to logout.\n"));
			//fprintf(stderr, "UKEY未能成功登出\n");
			break;
		case(UKEY_LIBRARY_LOAD_ERROR) :
			fprintf(stderr, _("Failed to initialize UKey.\n"));
			//fprintf(stderr, "UKEY初始化失败\n");
			break;
		case(SERIAL_NUMBER_MATCH_ERROR) :
			fprintf(stderr, _("The UKey dismatches with LICENSE file.\n"));
			//fprintf(stderr, "LICENSE的服务序列号与UKEY所含服务序列号不符\n");
			break;
		case(UKEY_EXPIRE_DEAL_HYPHEN_ERROR) :
			fprintf(stderr, _("Failed to deal with expiration date in UKey.\n"));
			//fprintf(stderr, "UKEY激活到期时间处理失败\n");
			break;
		case(UKEY_ACTIVATE_SYSTEM_FAILED) :
			fprintf(stderr, _("Failed to activate system via UKey.\n"));
			//fprintf(stderr, "UKEY激活系统失败\n");
			break;
		case(HAS_NORMALLY_ACTIVATED) :
			fprintf(stderr, _("System has already been activated, There is no need to activate it again.\n"));
			//fprintf(stderr, "系统已经激活，无须重复激活\n");
			break;
                case(HAS_ACTIVATED_WITH_ANOTHER_UKEY) :
			fprintf(stderr, _("System has already been activated by another UKey, There is no need to activate it again.\n"));
			//fprintf(stderr, "系统已经由其他UKEY激活过，无须重复激活\n");
			if(string_valid(info.kyinfo_ukey))
				fprintf(stderr, _("ID of UKey that activates this system: %s\n"), info.kyinfo_ukey);
				//fprintf(stderr, "激活该系统的UKEY编号： %s\n", kyinfo_ukey);
			break;
		case(UKEY_INIT_ERROR) :
			fprintf(stderr, _("Failed to initialize UKey environment.\n"));
			//fprintf(stderr, "UKEY环境初始化异常\n");
			break;
		case(UKEY_CONTENT_ERROR) :
			fprintf(stderr, _("Failed to get information of UKey.\n"));
			break;
		case(GPGME_ENCRYPT_ERROR) :
			fprintf(stderr, _("Failed to encrypt UKey's information.\n"));
			break;
		case(INVALID_SIGNATURE) :
			fprintf(stderr, _("Invalid signature.\n"));
			break;
#ifdef CHECK_ENV
		case(NON_KYLIN_PACKAGE) :
			if(strlen(env_check_wrong) > 0)
			{
				fprintf(stderr, _("Kylin provided package is modified: %s.\n"), env_check_wrong);
				break;
			}
			else
			{
				fprintf(stderr, _("Kylin provided package is modified.\n"));
				break;
			}
		case(MODIFIED_FILE_ERROR) :
			if(strlen(env_check_wrong) > 0)
			{
				fprintf(stderr, _("Kylin provided file is modified: %s.\n"), env_check_wrong);
				break;
			}
			else
			{
				fprintf(stderr, _("Kylin provided file is modified.\n"));
				break;
			}
#endif
		case(SERIAL_NUMBER_VALIDATION_ERROR) :
			fprintf(stderr, _("Invalid serial number.\n"));
			break;
		case(NO_SERIAL_NUMBER_ERROR) :
			fprintf(stderr, _("There is no valid serial number.\n"));
			break;
		case(INVALID_OVERWRITE_SERIAL_NUMBER_ERROR) :
			fprintf(stderr, _("Cannot overwrite original serial number.\n"));
			break;
		case(LICENSE_SERIAL_NUMBER_VALIDATION_ERROR) :
			fprintf(stderr, _("License serial number is invalid.\n"));
			break;
		case(UKEY_SERIAL_NUMBER_VALIDATION_ERROR) :
			fprintf(stderr, _("Ukey license serial number is invalid.\n"));
			break;
		case(PRODUCT_TYPE_MATCH_ERROR) :
			fprintf(stderr, _("Product type doesn't match.\n"));
			break;
		case(LICENSE_NO_PLATFORM_ERROR) :
			fprintf(stderr, _("License file doesn't contain platform information.\n"));
			break;
		case(LICENSE_PLATFORM_MATCH_ERROR) :
			fprintf(stderr, _("Platform doesn't match.\n"));
			break;
		case(PRODUCE_NUMBER_MATCH_ERROR) :
			fprintf(stderr, _("Produce number doesn't match.\n"));
			break;
		case(ACTIVATION_SERIAL_NUMBER_MATCH_ERROR) :
			fprintf(stderr, _("The serial number dismatches with LICENSE file.\n"));
			break;
		case(NO_ERROR) :
			break;
		default :
			fprintf(stderr, _("Other error\n"));
			//fprintf(stderr, "其他错误\n");
			break;
	}
}

#ifdef __aarch64__
/*
static void _str_tolower(char *str)
{
	char *p;

	if(!str)
		return;

	p = str;

	while('\0' != *p)
	{
		p = g_utf8_find_next_char(p, NULL);
		if(isupper(*p))
			*p = (char)tolower(*p);
	}
}
*/

/*
 * _class_string_match, check if system class string contains class string
 * return 1 if contains, or 0 if not
 */
static int _class_string_match(const char* class, const char* system_class)
{
	char _class[BUF_SIZE];
	char _system_class[BUF_SIZE];

	if(!class || !system_class)
		return 0;

	memset(_class, 0, BUF_SIZE);
	memset(_system_class, 0, BUF_SIZE);

	memcpy(_class, class, strlen(class));
	memcpy(_system_class, system_class, strlen(system_class));

//	_str_tolower(_class);
//	_str_tolower(_system_class);

	if(strcasestr(_system_class, _class))
		return 1;
	
	return 0;
}

/*
 * _get_system_class_from_uname, get system class string from uname release
 * return 0 if succeed, or -1 if not
 */
static int _get_system_class_from_uname(char* buf, size_t size)
{
	struct utsname un;
	size_t len;

	if(uname(&un) !=0)
		return -1;

	len = strlen(un.release) + 1;

	if(len > size)
		return -1;

	memset(buf, 0, size);
	memcpy(buf, un.release, len);

	return 0;
}

/*
 * _get_system_class_from_osinfo, get system class string from osinfo file
 * return 0 if succeed, or -1 if not
 */
static int _get_system_class_from_osinfo(char* buf, size_t size)
{
	FILE* fp = NULL;
	char line[BUF_SIZE] = {0};

	fp = fopen(OSINFO_PATH, "r");
	if(fp == NULL)
		return -1;

	while(fgets(line, sizeof(line), fp) != NULL)
	{
		if(strncasecmp(line, "OS", strlen("OS")) == 0)
		{
			int len = strlen(line);
			if(len < size)
			{
				memcpy(buf, line, len);
				buf[len] = '\0';
			} else {
				memcpy(buf, line, size);
				buf[size - 1] = '\0';
			}
			break;
		}
	}
        fclose(fp);
	return 0;
}

/*
 * _class_match, check if class string matches system class
 * return 1 if matches, or 0 if not
 */
static int _class_match(const char* class)
{
	char buf[BUF_SIZE] = {0};
	int ret;

	ret = _get_system_class_from_osinfo(buf, sizeof(buf));
	if(ret < 0)
		goto from_uname;
	if(_class_string_match(class, buf))
		return 1;

from_uname:
	memset(buf, 0, sizeof(buf));
	ret = _get_system_class_from_uname(buf, sizeof(buf));
	if(0 != ret)
		return 0;

	return _class_string_match(class, buf);
}

#endif

/*
 * log_write, write log to /var/log/kylin-activation-check
 */
void log_write(const char* log_file, const char* message, const char* type, int log);

static int has_ever_activated(const char* serial_no)
{
	int ret = 0;
	char* old_code = NULL;
	struct tm* old_expire = NULL;
	char* hw_info = NULL;
	char* register_code = NULL;

	if(!serial_no)
	{
		ret = NOT_ACTIVATED;
		goto out;
	}

	if(!_serial_validation_check(serial_no))
	{
		ret = NOT_ACTIVATED;
		goto out;
	}
	hw_info = hardware_id_save_no_kyhwid();
	// syslog(LOG_INFO,"* [%s]\n",hw_info);

	if(!hw_info)
	{
		ret = NOT_ACTIVATED;
		goto out;
	}
	// serial_no = "100000";
	// hw_info = "00:11:22:04:8b:62";
	register_code = encrypted_number_generate_register(hw_info, serial_no, "");
	// printf("register code:%s\n",register_code);
	if(!register_code)
	{
		ret = NOT_ACTIVATED;
		goto out;
	}

	old_code = activation_code_load(activate_file);
	if(old_code)
	{
		if(NULL != (old_expire = activation_expire_date_normal(hw_info, serial_no, old_code)))
		{
			ret = ACTIVATED;
			goto out;
		} else if (NULL != (old_expire = activation_expire_date_ukey(register_code, string_address(info.kyinfo_ukey), old_code)))
		{
			ret = ACTIVATED;
			goto out;
		}
	}

out:
	if(register_code)
		free(register_code);
	if(hw_info)
		free(hw_info);
	if(old_code)
		free(old_code);
	if(old_expire)
		free(old_expire);

	return ret;
}

/*
 * _kylin_activation_check_platform, check system architecture information.
 */
int _kylin_activation_check_platform(const char* l_file);

/*
 * _kylin_activation_system_os_check, check system version information.
 */
static int _kylin_activation_system_os_check(const char* l_file, const char* i_file);

/*
 * _kylin_activation_validation_check, validate system's activation related file: LICENSE file, kyinfo file and activation file
 * return NO_ERROR if succeed, or error number if not
 */
static int _kylin_activation_validation_check(const char* l_file, const char* i_file, const char* a_file);

/*
 * _set_error_code, set error number to ret
 */
inline static void _set_error_code(int *ret, int error_num)
{
	if(ret)
		*ret = error_num;
}

/*
 * kylin_activation_validation_check_with_path, validate system's activation related file with path: LICENSE file, kyinfo file and activation file
 * return NO_ERROR if succeed, or error number if not
 */
int kylin_activation_validation_check_with_path(const char* l_file, const char* i_file, const char* a_file)
{
	return _kylin_activation_validation_check(l_file, i_file, a_file);
}

/*
 * kylin_activation_validation_check, validate system's activation related file: LICENSE file, kyinfo file and activation file
 * return NO_ERROR if succeed, or error number if not
 */
static int kylin_activation_validation_check()
{
	return _kylin_activation_validation_check(KYLIN_LICENSE_FILE, KYLIN_INFORMATION_FILE, KYLIN_ACTIVATION_FILE);
}



/*
 * _serial_number_mode, get serial number mode
 */
int _serial_number_mode(const char* serial)
{
	int length;

	if(!serial)
		return SERIAL_MODE_UNKNOWN;

	length = strlen(serial);
	if(length == LEGACY_SERIAL_LEN)
	{
		return SERIAL_MODE_LEGACY;
	} else if (length >= NEW_SERIAL_LEN) {
		return SERIAL_MODE_NEW;
	} else if (length == BATCH_SERIAL_LEN) {
		return SERIAL_MODE_BATCH;
	}

	return SERIAL_MODE_UNKNOWN;
}

/*
 * _serial_legacy_mode, check if a serial number can be used in legacy mode
 */
/*
static bool _serial_legacy_mode(const char* serial)
{
	int length;

	if (!serial)
		return false;

	length = strlen(serial);
	if (length == LEGACY_SERIAL_LEN || length >= NEW_SERIAL_LEN)
		return true;

	return false;
}
*/

/*
 * _kylin_activation_check_platform, check system architecture information.
 */
int _kylin_activation_check_platform(const char* l_file)
{
	int result = -1;
	GKeyFile *key_file_license = NULL;
	char* license_platform = NULL;
	char* custom_info = NULL;
	unsigned long custom_info_size = 0;

	license_file = (char*)(l_file);

	result = gpg_verify(license_file, &custom_info, &custom_info_size);
	if(result != NO_ERROR)
		goto _validation_out;

	if(!key_file_license)
		key_file_license = license_convert_to_keyfile(custom_info, custom_info_size, ':', '=');
	if(!key_file_license)
	{
		result = LICENSE_DATA_FORMAT_ERROR;
		goto _validation_out;
	}

	if(!license_platform)
		license_platform = key_file_get_value(key_file_license, LICENSE_GROUP, "PLATFORM");
	if(!license_platform || strcmp(license_platform, "None") == 0)
	{
		g_key_file_free(key_file_license);
		key_file_license = NULL;
		result = LICENSE_NO_PLATFORM_ERROR;
		goto _validation_out;
	}
	if(strcmp(license_platform, PLATFORM_STRING) != 0)
	{
		result = LICENSE_PLATFORM_MATCH_ERROR;
		goto _validation_out;
	}

_validation_out:

	if (key_file_license)
	{
		g_key_file_free(key_file_license);
		key_file_license = NULL;
	}

	if (license_platform)
	{
		free(license_platform);
		license_platform = NULL;
	}

	if(result != NO_ERROR)
	{
		return result;
	}

	if(custom_info) {
		free(custom_info);
		custom_info = NULL;
	}

	return NO_ERROR;
}

/*
 * _kylin_activation_system_os_check, check system version information.
 */
static int _kylin_activation_system_os_check(const char* l_file, const char* i_file)
{
	int ret=-1;
	char* prettyName=NULL;
	char* distid=NULL;
	GKeyFile* keyFile=NULL;
	GKeyFile *keyFileKyinfo = NULL;
	char* custom_info = NULL;
	char* osName = NULL;
	char* path = NULL;
	unsigned long custom_info_size = 0;

	//获取/etc/LICENSE的OSNAME
	int result = gpg_verify(l_file, &custom_info, &custom_info_size);
	if(result == NO_ERROR)
	{
		keyFile = license_convert_to_keyfile(custom_info, custom_info_size, ':', '=');
	}
	if(keyFile)
		osName=key_file_get_value(keyFile, LICENSE_GROUP, "OSNAME");

	//获取/etc/.kyinfo的dist_id
	keyFileKyinfo=key_file_load_from_file(i_file);
	if(keyFileKyinfo)
	{
		distid=key_file_get_value(keyFileKyinfo,"dist","dist_id");
	}

	//获取/etc/os-release的PRETTY_NAME
	if(access("/etc/os-release-variant",F_OK)==0)
		path="/etc/os-release-variant";
	else
		path = "/etc/os-release";
	char buf[256] = {0};
	FILE *fp = fopen(path, "r");
	if (NULL != fp)
	{
		while (NULL != fgets(buf, 256, fp))
		{
			if (strlen(buf) > 11)
			{
				if (0 == strncmp(buf, "PRETTY_NAME", 11))
				{
					long int start=strchr(buf,'"');//第一次出现"的位置
					long int end=strrchr(buf,'"');//最后一次出现"的位置
					int len=end-start-1;//两个"之间的字符个数
					prettyName=(char *)malloc(sizeof(char) * (len+1));
					strncpy(prettyName,strchr(buf,'"')+1,len);
					prettyName[len]='\0';
					break;
				}
			}
		}
		fclose(fp);
	}

	if(osName)//LICENSE中存在OSNAME字段
	{
		if(prettyName)
		{
			if (access("/etc/os-release-variant", F_OK) == 0)
			{
				if (0 == strcmp(osName, prettyName))
					ret = 0;
			}
			else
			{
				if (0 == strncmp(osName, "Kylin V10 SP1", 12) ||
					 0 == strcmp(osName, "Kylin V10 Professional") ||
					  0 == strcmp(osName, "Kylin V10.1"))
				{
					ret = 0;
				}
			}
		}
	}
	else
	{
		if(prettyName && distid)
		{
			if (0 == strncmp(distid, "Kylin-Desktop-V10-Professional", 30) ||
				 0 == strncmp(distid, "Kylin-Desktop-V10-SP1", 20) ||
				 0 == strncmp(distid, "Kylin-Desktop-V10.1", 19))
			{
				ret = 0;
			}
		}
	}

	if(prettyName)
	{
		free(prettyName);
		prettyName=NULL;
	}
	if(distid)
	{
		free(distid);
		distid=NULL;
	}
	if(custom_info)
	{
		free(custom_info);
		custom_info = NULL;
	}
	if(keyFile)
		g_key_file_free(keyFile);
	if(keyFileKyinfo)
		g_key_file_free(keyFileKyinfo);
	if(osName)
		free(osName);
	return ret;
}

/*
 * _kylin_activation_validation_check, validate system's activation related file: LICENSE file, kyinfo file and activation file
 * return NO_ERROR if succeed, or error number if not
 */
static int _kylin_activation_validation_check(const char* l_file, const char* i_file, const char* a_file)
{
	int result = -1;
	GKeyFile *key_file_license = NULL;
	GKeyFile *key_file_kyinfo = NULL;
	char* license_serial = NULL;
	int license_serial_mode = SERIAL_MODE_UNKNOWN;
	char* license_trial = NULL;
	char* license_to = NULL;
	char* license_platform = NULL;
	char* custom_info = NULL;
	unsigned long custom_info_size = 0;
	char* kyinfo_term = NULL;
	char* kyinfo_ukey = NULL;
	char* kyinfo_serial = NULL;
	char* kyinfo_to = NULL;
#ifdef __aarch64__
	char* license_class = NULL;
#endif

#ifdef CHECK_ENV
	int env_check_ret = -1;
#endif
	bool need_check_serial = true;

	license_file = (char*)l_file;
	info_file = (char*)i_file;
	activate_file = (char*)a_file;

	i18n_initial();

#ifdef CHECK_ENV
	memset(env_check_wrong, 0, BUF_SIZE);
	memset(env_check_error, 0, BUF_SIZE);

	env_check_ret = kylin_env_check(env_check_wrong);

	if(NO_ERROR == env_check_ret)
		kylin_activation_env_contact();

#endif
	if(access(l_file,F_OK) != 0 || access(i_file,F_OK) != 0)
	{
		result = LICENSE_DETECTION_FAIL;
		goto _validation_out;
	}

	result=_kylin_activation_check_platform(l_file);
	if( result != NO_ERROR)
	{
		goto _validation_out;
	}

	if (_kylin_activation_system_os_check(l_file, i_file) != NO_ERROR)
	{
		result = SYSTEM_VERSION_INFORMATION_MATCH_ERROR;
		goto _validation_out;
	}

	if(!key_file_kyinfo)
		key_file_kyinfo = key_file_load_from_file(info_file);
	if(!key_file_kyinfo)
	{
		result = KYINFO_ERROR;
		goto _validation_out;
	}

	kyinfo_term = key_file_get_value(key_file_kyinfo, "os", "term");
	if(kyinfo_term && (0 == strcmp(kyinfo_term, "None")))
		kyinfo_term = NULL;
	if(kyinfo_term)
	{
		bzero(info.kyinfo_term, sizeof(info.kyinfo_term));
		strcpy(info.kyinfo_term, kyinfo_term);
	}

	kyinfo_ukey = key_file_get_value(key_file_kyinfo, "servicekey", "ukey");
	if(kyinfo_ukey && (0 == strcmp(kyinfo_ukey, "None")))
		kyinfo_ukey = NULL;
	if(kyinfo_ukey)
	{
		bzero(info.kyinfo_ukey, sizeof(info.kyinfo_ukey));
		strcpy(info.kyinfo_ukey, kyinfo_ukey);
	}

	kyinfo_to = key_file_get_value(key_file_kyinfo, "os", "to");
	if(kyinfo_to && (0 == strcmp(kyinfo_to, "None")))
		kyinfo_to = NULL;
	if(kyinfo_to)
	{
		bzero(info.kyinfo_to, sizeof(info.kyinfo_to));
		strcpy(info.kyinfo_to, kyinfo_to);
	}

	kyinfo_serial = key_file_get_value(key_file_kyinfo, "servicekey", "key");
	if(kyinfo_serial && (0 == strcmp(kyinfo_serial, "None")))
		kyinfo_serial = NULL;

#ifdef CHECK_ENV
	if(NO_ERROR != env_check_ret)
	{
		result = env_check_ret;
		goto _validation_out;
	}
#endif

	//kylin_activation_clear_kyinfo(key_file_kyinfo, info_file);

	result = gpg_verify(license_file, &custom_info, &custom_info_size);
	if(result != NO_ERROR)
		goto _validation_out;

	if(!key_file_license)
		key_file_license = license_convert_to_keyfile(custom_info, custom_info_size, ':', '=');
	if(!key_file_license)
	{
		result = LICENSE_DATA_FORMAT_ERROR;
		goto _validation_out;
	}


	if(!license_serial)
		license_serial = key_file_get_value(key_file_license, LICENSE_GROUP, "SERIAL");
	if(!license_serial || strcmp(license_serial, "None") == 0)
	{
		g_key_file_free(key_file_license);
		key_file_license = NULL;
		result = LICENSE_SERIAL_ERROR;
		goto _validation_out;
	}
	if(license_serial)
	{
		bzero(info.license_serial, sizeof(info.license_serial));
		strcpy(info.license_serial, license_serial);
	}

	if(kyinfo_serial)
	{
		if(NO_ERROR != serial_number_match_check(license_serial, kyinfo_serial))
		{
			free(kyinfo_serial);
			kyinfo_serial = NULL;
		} else {
			bzero(info.real_serial, sizeof(info.real_serial));
			strcpy(info.real_serial, kyinfo_serial);
		}
	}

	license_serial_mode = _serial_number_mode(license_serial);
	if((SERIAL_MODE_LEGACY == license_serial_mode) || (SERIAL_MODE_NEW == license_serial_mode))
	{
		need_check_serial = false;
		bzero(info.real_serial, sizeof(info.real_serial));
		strcpy(info.real_serial, license_serial);
		key_file_set_value(key_file_kyinfo, "servicekey", "key", license_serial);
	} else {
		if(kyinfo_serial)
		{
			if(!_serial_validation_check(kyinfo_serial))
			{
				key_file_set_value(key_file_kyinfo, "servicekey", "key", license_serial);
			}
		} else {
			key_file_set_value(key_file_kyinfo, "servicekey", "key", license_serial);
		}
	}

#ifdef __aarch64__
	if(!license_class)
		license_class = key_file_get_value(key_file_license, LICENSE_GROUP, "CLASS");
	if(!license_class || strcmp(license_class, "None") == 0)
	{
		g_key_file_free(key_file_license);
		key_file_license = NULL;
		result = LICENSE_NO_CLASS_ERROR;
		goto _validation_out;
	}

	if(!_class_match(license_class))
	{
		result = LICENSE_CLASS_MATCH_ERROR;
		goto _validation_out;
	}

	if(license_class)
	{
		bzero(info.license_class, sizeof(info.license_class));
		strcpy(info.license_class, license_class);
	}
#endif


	if(!license_trial)
		license_trial = key_file_get_value(key_file_license, LICENSE_GROUP, "TERM");
	if(license_trial && strcmp(license_trial, "None") == 0)
		license_trial = NULL;
	if(license_trial)
	{
		bzero(info.license_trial, sizeof(info.license_trial));
		strcpy(info.license_trial, license_trial);
	}

	if(!license_to)
		license_to = key_file_get_value(key_file_license, LICENSE_GROUP, "TO");
	if(license_to && strcmp(license_to, "None") == 0)
		license_to = NULL;
	if(license_to)
	{
		bzero(info.license_to, sizeof(info.license_to));
		strcpy(info.license_to, license_to);
	}

	if(!license_platform)
		license_platform = key_file_get_value(key_file_license, LICENSE_GROUP, "PLATFORM");
	if(!license_platform || strcmp(license_platform, "None") == 0)
	{
		g_key_file_free(key_file_license);
		key_file_license = NULL;
		result = LICENSE_NO_PLATFORM_ERROR;
		goto _validation_out;
	}
	if(strcmp(license_platform, PLATFORM_STRING) != 0)
	{
		result = LICENSE_PLATFORM_MATCH_ERROR;
		goto _validation_out;
	}
	if(license_platform)
	{
		bzero(info.license_platform, sizeof(info.license_platform));
		strcpy(info.license_platform, license_platform);
	}

	if(string_valid(info.old_expire_date))
		key_file_set_value(key_file_kyinfo, "os", "term", info.old_expire_date);
	else if(license_trial)
		key_file_set_value(key_file_kyinfo, "os", "term", license_trial);
	else if(kyinfo_term)
		key_file_set_value(key_file_kyinfo, "os", "term", kyinfo_term);

	key_file_save_to_file(key_file_kyinfo, info_file);

	if(need_check_serial)
	{
		if(has_ever_activated(license_serial))
		{
			bzero(info.real_serial, sizeof(info.real_serial));
			strcpy(info.real_serial, license_serial);
		} else if(has_ever_activated(kyinfo_serial)) {
			bzero(info.real_serial, sizeof(info.real_serial));
			strcpy(info.real_serial, kyinfo_serial);
		}
	}

_validation_out:

	if (key_file_license)
	{
		g_key_file_free(key_file_license);
		key_file_license = NULL;
	}

	if (key_file_kyinfo)
	{
		g_key_file_free(key_file_kyinfo);
		key_file_kyinfo = NULL;
	}

	if (license_serial)
	{
		free(license_serial);
		license_serial = NULL;
	}

	if (license_trial)
	{
		free(license_trial);
		license_trial = NULL;
	}

	if (license_to)
	{
		free(license_to);
		license_to = NULL;
	}

	if (license_platform)
	{
		free(license_platform);
		license_platform = NULL;
	}

	if (custom_info)
	{
		free(custom_info);
		custom_info = NULL;
	}

	if (kyinfo_term)
	{
		free(kyinfo_term);
		kyinfo_term = NULL;
	}

	if (kyinfo_ukey)
	{
		free(kyinfo_ukey);
		kyinfo_ukey = NULL;
	}

	if (kyinfo_serial)
	{
		free(kyinfo_serial);
		kyinfo_serial = NULL;
	}

	if (kyinfo_to)
	{
		free(kyinfo_to);
		kyinfo_to = NULL;
	}

#ifdef __aarch64__
	if (license_class)
	{
		free(license_class);
		license_class = NULL;
	}
#endif

#ifdef CHECK_ENV
	if(NO_ERROR != env_check_ret)
		result = env_check_ret;
#endif

	if(result != NO_ERROR)
	{
		//kylin_activation_clear_kyinfo(key_file_kyinfo, info_file);
		return result;
	}

	return NO_ERROR;
}


/*
 * kylin_activation_verify, verify LICENSE file and print plain text of LICENSE file  
 * return NO_ERROR if succeed, or error number if not
 */
int kylin_activation_verify()
{
	int ret = -1;
	char* _custom_info = NULL;
	unsigned long _custom_info_size = 0;

	ret = kylin_activation_validation_check();
	if(ret != NO_ERROR)
		return ret;

	ret = gpg_verify(license_file, &_custom_info, &_custom_info_size);
	if(ret != NO_ERROR)
		return ret;

	if(_custom_info)
	{
		printf("\n%-*.*s", (int)_custom_info_size, (int)_custom_info_size, _custom_info);
		free(_custom_info);
	}

	return ret;
}

/*
 * kylin_activation_get_customer, get customer info.
 */
char* kylin_activation_get_customer(int* result)
{
	int ret = -1;
	char* customer_info = NULL;

	ret = kylin_activation_validation_check();
	if(ret != NO_ERROR)
	{
		_set_error_code(result, ret);
		return NULL;
	}

	if(string_valid(info.kyinfo_to))
	{
		customer_info = strdup(info.kyinfo_to);
	}

	return customer_info;
}

/*
 * kylin_activation_set_customer, set customer info.
 */
int kylin_activation_set_customer(const char* customer)
{
	int ret = -1;

	if(!customer || (strlen(customer) == 0))
		return OTHER_ERROR;

	ret = kylin_activation_validation_check();
	if(ret != NO_ERROR)
		return ret;

	kylin_activation_kyinfo_set_value(info_file, "os", "to", customer);

	return NO_ERROR;
}

/*
 * kylin_activation_get_serial_number, get serial number
 * return serial number string if succeed and set result with NO_ERROR, 
 * or return NULL and set result with error number
 */
char* kylin_activation_get_serial_number(int* result)
{
	int ret = -1;
	char* serial_no = NULL;

	ret = kylin_activation_validation_check();
	if(ret != NO_ERROR)
	{

		_set_error_code(result, ret);
		return NULL;
	}

	if(string_valid(info.real_serial))
		serial_no = strdup(info.real_serial);

	if(!serial_no)
	{
		if(string_valid(info.license_serial))
			serial_no = strdup(info.license_serial);
	}

	if(!serial_no)
	{
		_set_error_code(result, NO_SERIAL_NUMBER_ERROR);
		return NULL;
	}

	_set_error_code(result, NO_ERROR);

	return serial_no;
}

/*
 * kylin_activation_can_set_serial_number, check if serial number can be set.
 * return 1 if serial number can be set, or return 0;
 */
int kylin_activation_can_set_serial_number(int *result)
{
	int ret = -1;
	ret = kylin_activation_validation_check();
	if(ret != NO_ERROR)
	{
		_set_error_code(result, ret);
		return 0;
	}

	_set_error_code(result, NO_ERROR);

	if(strlen(info.license_serial) == BATCH_SERIAL_LEN)
		return 1;

	return 0;
}

/*
 * _kylin_activation_get_register_number, get register number
 * return register number string if succeed and set result with NO_ERROR, 
 * or return NULL and set result with error number
 */
char* _kylin_activation_get_register_number(const char* serial_no, int* result)
{
	char* register_no_hyphen = NULL;
	char* hw_info = NULL;

	if(!serial_no)
	{
		_set_error_code(result, NO_SERIAL_NUMBER_ERROR);
		return NULL;
	}

	if(!_serial_validation_check(serial_no))
	{
		_set_error_code(result, SERIAL_NUMBER_VALIDATION_ERROR);
		return NULL;
	}

	hw_info = hardware_id_save_no_kyhwid();
	if(!hw_info)
	{
		_set_error_code(result, HARDWARE_INFORMATION_ERROR);
		return NULL;
	}

	register_no_hyphen = encrypted_number_generate_register(hw_info, serial_no, "");

	if(!register_no_hyphen)
	{
		free(hw_info);
		hw_info = NULL;
		_set_error_code(result, REGISTER_CREATION_ERROR);
		return NULL;
	}


	_set_error_code(result, NO_ERROR);

	if (hw_info) {
		free(hw_info);
		hw_info = NULL;
	}
	return register_no_hyphen;
}

/*
 * kylin_activation_get_register_number_with_serial, get register number
 * return register number string if succeed and set result with NO_ERROR, 
 * or return NULL and set result with error number
 */
char* kylin_activation_get_register_number_with_serial(const char* serial_no, int* result)
{
	char* register_with_hyphen = NULL;
	char* register_no_hyphen = NULL;
	int ret = -1;

	ret = kylin_activation_validation_check();
	if(ret != NO_ERROR)
	{
		_set_error_code(result, ret);
		return NULL;
	}

	ret = serial_number_match_check(string_address(info.license_serial), serial_no);
	if(ret != NO_ERROR)
	{
		_set_error_code(result, ret);
		return NULL;
	}

	register_no_hyphen = _kylin_activation_get_register_number(serial_no, &ret);
	if(!register_no_hyphen)
	{
		_set_error_code(result, ret);
		return NULL;
	}

	register_with_hyphen = code_add_hyphen(register_no_hyphen);
	free(register_no_hyphen);
	register_no_hyphen = NULL;

	if(!register_with_hyphen)
	{
		_set_error_code(result, REGISTER_DEAL_HYPHEN_ERROR);
		return NULL;
	}

	_set_error_code(result, NO_ERROR);

	return register_with_hyphen;
}

/*
 * kylin_activation_get_register_number, get register number
 * return register number string if succeed and set result with NO_ERROR, 
 * or return NULL and set result with error number
 */
char* kylin_activation_get_register_number(int* result)
{
	char* register_with_hyphen = NULL;
	char* register_no_hyphen = NULL;
	int ret = -1;
	uid = getpid();

	ret = kylin_activation_validation_check();
	if(ret != NO_ERROR)
	{
		_set_error_code(result, ret);
		return NULL;
	}

	register_no_hyphen = _kylin_activation_get_register_number(string_address(info.real_serial), &ret);
	if(!register_no_hyphen)
	{
		_set_error_code(result, ret);
		return NULL;
	}

	if ( ret != NO_ERROR ) {
		_set_error_code(result, ret);
		free(register_no_hyphen);
		return NULL;
	}

	register_with_hyphen = code_add_hyphen(register_no_hyphen);
	free(register_no_hyphen);
	register_no_hyphen = NULL;

	if(!register_with_hyphen)
	{
		_set_error_code(result, REGISTER_DEAL_HYPHEN_ERROR);
		return NULL;
	}

	_set_error_code(result, NO_ERROR);

	return register_with_hyphen;
}

/*
 * _kylin_activation_get_qrcode, get qrcode
 * return qrcode string if succeed and set result with NO_ERROR, 
 * or return NULL and set result with error number
 */
static char* _kylin_activation_get_qrcode(const char* serial_no, int* result)
{
	char* hw_info = NULL;
	char* buf = NULL;
	char* qrcode = NULL;
	int ret = -1;
	unsigned int out_size = 0;
	unsigned char encrypted_info[OUT_BUF_SIZE] = {0};

	if(!serial_no)
	{
		_set_error_code(result, NO_SERIAL_NUMBER_ERROR);
		return NULL;
	}

	if(!_serial_validation_check(serial_no))
	{
		_set_error_code(result, SERIAL_NUMBER_VALIDATION_ERROR);
		return NULL;
	}
	
	hw_info = hardware_id_save_no_kyhwid();
	if(!hw_info)
	{
		_set_error_code(result, HARDWARE_INFORMATION_ERROR);
		goto qrcode_out;
	}

	memset(encrypted_info, 0, sizeof(encrypted_info));
	ret = encrypt_hardware_info(hw_info, strlen(hw_info), encrypted_info, &out_size);
	if(ret != NO_ERROR)
	{
		_set_error_code(result, ret);
		goto qrcode_out;
	}

	encrypted_info[out_size] = '\0';

	if (SERIAL_MODE_BATCH == _serial_number_mode(string_address(info.license_serial)))
	{
		buf = g_strconcat("http://wx.kylinos.cn/qywx/distro/activate?f=",
					serial_no, "&y=", encrypted_info, 
                                        "&p=", string_address(info.license_serial), NULL);
	} else {
		buf = g_strconcat("http://wx.kylinos.cn/qywx/distro/activate?f=",
					serial_no, "&y=", encrypted_info, NULL);
	}

	if(buf)
	{
		qrcode = strdup(buf);
	}

	if(!qrcode)
	{
		_set_error_code(result, QRCODE_CREATION_ERROR);
		goto qrcode_out;
	}	

	_set_error_code(result, NO_ERROR);

qrcode_out:
	if(hw_info)
	{
		free(hw_info);
	}

	if(buf)
	{
		free(buf);
	}

	return qrcode;
}

/*
 * kylin_activation_get_qrcode_with_serial, get qrcode
 * return qrcode string if succeed and set result with NO_ERROR, 
 * or return NULL and set result with error number
 */
char* kylin_activation_get_qrcode_with_serial(const char* serial_no, int* result)
{
	int ret = -1;
	ret = kylin_activation_validation_check();
	if(ret != NO_ERROR)
	{
		_set_error_code(result, ret);
		return NULL;
	}

	ret = serial_number_match_check(string_address(info.license_serial), serial_no);
	if(ret != NO_ERROR)
	{
		_set_error_code(result, ret);
		return NULL;
	}

	return _kylin_activation_get_qrcode(serial_no, result);
}

/*
 * kylin_activation_get_qrcode, get qrcode
 * return qrcode string if succeed and set result with NO_ERROR, 
 * or return NULL and set result with error number
 */
char* kylin_activation_get_qrcode(int* result)
{
	int ret = -1;
	ret = kylin_activation_validation_check();
	if(ret != NO_ERROR)
	{
		_set_error_code(result, ret);
		return NULL;
	}

	return _kylin_activation_get_qrcode(string_address(info.real_serial), result);
}

/*
 * _kylin_activation_get_hardware_info, get hardware information
 * return hardware information if succeed and set result with NO_ERROR,
 * or return NULL and set result with error number
 */
static char* _kylin_activation_get_hardware_info(int* result)
{
	char* hw_info = NULL;
	hw_info = hardware_id_save_no_kyhwid();
	if(!hw_info)
	{
		_set_error_code(result, HARDWARE_INFORMATION_ERROR);
		return NULL;
	}

	_set_error_code(result, NO_ERROR);
	return hw_info;
}

/*
 * kylin_activation_get_hardware_info, get hardware information
 * return hardware information if succeed and set result with NO_ERROR,
 * or return NULL and set result with error number
 */
char* kylin_activation_get_hardware_info(int* result)
{
	return _kylin_activation_get_hardware_info(result);
}

/*
 * kylin_activation_get_encrypted_hardware_info, get encrypted hardware information
 * return hardware information if succeed and set result with NO_ERROR,
 * or return NULL and set result with error number
 */
char* kylin_activation_get_encrypted_hardware_info(int* result)
{
	char* hw_info = NULL;
	char* encrypted_info = NULL;
	int ret;
	unsigned int out_size = 0;
	char buffer[OUT_BUF_SIZE] = {0};

	hw_info = _kylin_activation_get_hardware_info(result);
	if(!hw_info)
	{
		goto out;
	}

	memset(buffer, 0, sizeof(buffer));
	ret = encrypt_hardware_info(hw_info, strlen(hw_info), (unsigned char*)buffer, &out_size);
	if(ret != NO_ERROR)
	{
		_set_error_code(result, ret);
		goto out;
	}

	buffer[out_size] = '\0';

	encrypted_info = strdup(buffer);
	if(!encrypted_info)
	{
		_set_error_code(result, INFO_ENCRYPT_ERROR);
		goto out;
	}

	_set_error_code(result, NO_ERROR);

out:
	if(hw_info)
		free(hw_info);

	return encrypted_info;
}

/*
 * _kylin_activation_trial_status, get trial status
 * return 1 if on trial, or 0 if not
 */
static int _kylin_activation_trial_status()
{
	if(!string_valid(info.license_trial))
		return NOT_ON_TRIAL;

	if(!date_string_expired(string_address(info.license_trial)))
		return ON_TRIAL;

	return NOT_ON_TRIAL;
}

/*
 * _kylin_activation_trial_status, get trial status
 * return 1 if on trial and set result to NO_ERROR, or 0 if not and set result
 */
int kylin_activation_trial_status(int* result)
{
	int ret = -1;
	char* message = NULL;

	_set_error_code(result, NO_ERROR);
	if (license_should_escape())
	{
		return 1;
	}

	ret = kylin_activation_validation_check();
	if(ret != NO_ERROR)
	{
		_set_error_code(result, ret);

		message = kylin_activation_get_result_message(ret);
		if(message)
		{
			log_write(LOG_FILE, message, "EE", 1);
		}

		return NOT_ON_TRIAL;
	}

	return _kylin_activation_trial_status();
}

/*
 * kylin_activation_activate_status, check if system is activated
 * return 1 if system is under activated status and set result with NO_ERROR, or 0 if not and set result
 */
int kylin_activation_activate_status(int* result)
{
	int ret = -1;
	char* message = NULL;

	ret = kylin_activation_validation_check();
	if(ret != NO_ERROR)
	{
		_set_error_code(result, ret);

		message = kylin_activation_get_result_message(ret);
		if(message)
		{
			log_write(LOG_FILE, message, "EE", 1);
		}
		return NOT_ACTIVATED;
	}
	else{
		if (license_should_escape())
		{
			_set_error_code(result, NO_ERROR);
			return 1;
		}
	}

	return _kylin_activation_activate_status(string_address(info.real_serial), result, 1);
}

/*
 * _kylin_activation_activate_status, check if system is activated
 * return 1 if system is under activated status, or 0 if not
 */
static int _kylin_activation_activate_status(const char* serial_no, int* result, int log)
{
	int ret = -1;
	char* old_code = NULL;
	struct tm* old_expire = NULL;
	char* hw_info = NULL;
	char* register_code = NULL;
	int expired = -1;
	int has_old_activation = 0;
	_set_error_code(result, NO_ERROR);

	if(!serial_no)
	{
		log_write(LOG_FILE, "无有效的服务序列号", "EE", log);
		_set_error_code(result, NO_SERIAL_NUMBER_ERROR);
		ret = NOT_ACTIVATED;

		goto activate_status_out;
	}

	if(!_serial_validation_check(serial_no))
	{
		log_write(LOG_FILE, "无效的服务序列号", "EE", log);
		_set_error_code(result, SERIAL_NUMBER_VALIDATION_ERROR);
		ret = NOT_ACTIVATED;

		goto activate_status_out;
	}

	hw_info = hardware_id_save_no_kyhwid();
	if(!hw_info)
	{
		//printf("无法查看激活状态\n");

		log_write(LOG_FILE, "无法查看激活状态", "EE", log);

		_set_error_code(result, HARDWARE_INFORMATION_ERROR);
		ret = NOT_ACTIVATED;

		goto activate_status_out;
	}

	register_code = encrypted_number_generate_register(hw_info, serial_no, "");
	if(!register_code)
	{
		log_write(LOG_FILE, "注册码生成失败", "EE", log);

		_set_error_code(result, REGISTER_CREATION_ERROR);
		ret = NOT_ACTIVATED;

		goto activate_status_out;
	}
	
	old_code = activation_code_load(activate_file);
	if(old_code)
	{
		if(NULL != (old_expire = activation_expire_date_normal(hw_info, serial_no, old_code)))
		{
			has_old_activation = 1;
			activation_status = NORMALLY_ACTIVATED;
		}
		else if(NULL != (old_expire = activation_expire_date_ukey(register_code, string_address(info.kyinfo_ukey), old_code)))
		{
			has_old_activation = 1;
			activation_status = WITH_UKEY_ACTIVATED;
		}
	}

	if(!has_old_activation)
	{
		//printf("系统未被激活\n");
		if(!_kylin_activation_trial_status())
			log_write(LOG_FILE, "系统未被激活，系统已过试用期", "EE", log);
		else
			log_write(LOG_FILE, "系统未被激活，系统在试用期内", "WW", log);
		ret = NOT_ACTIVATED;

		goto activate_status_out;
	}

	bzero(info.old_expire_date, sizeof(info.old_expire_date));
	sprintf(info.old_expire_date, "%4d-%02d-%02d",
			old_expire->tm_year + 1900,
			old_expire->tm_mon + 1,
			old_expire->tm_mday);


	expired = date_expired(old_expire);
	if(!expired && expired != INT_MAX)
	{
		char buf[BUF_SIZE];


		ret = ACTIVATED;
		//printf("系统已激活\n");
		log_write(LOG_FILE, "系统已经激活", "II", log);


		memset(buf, 0, BUF_SIZE);
		sprintf(buf, "%4d-%02d-%02d",
				old_expire->tm_year + 1900,
				old_expire->tm_mon + 1,
				old_expire->tm_mday);

		kylin_activation_kyinfo_set_value(info_file, "os", "term", buf);

		bzero(info.activate_file_date, sizeof(info.activate_file_date));
		strcpy(info.activate_file_date, buf);


	}
	else
	{
		ret = NOT_ACTIVATED;
		if(string_valid(info.old_expire_date))
		{
			kylin_activation_kyinfo_set_value(info_file, "os", "term", info.old_expire_date);
		}
		//printf("系统激活已到期\n");
		if(!_kylin_activation_trial_status())
			log_write(LOG_FILE, "系统激活已到期，系统已过试用期", "EE", log);
		else
			log_write(LOG_FILE, "系统激活已到期，系统在试用期内", "WW", log);
	}

	//printf("系统激活到期时间： %4d-%02d-%02d \n",
	//	old_expire->tm_year + 1900,
	//	old_expire->tm_mon + 1, 
	//	old_expire->tm_mday);


activate_status_out:
	if(register_code)
		free(register_code);
	if(hw_info)
		free(hw_info);
	if(old_code)
		free(old_code);
	if(old_expire)
		free(old_expire);

	return ret;

}

/*
 * kylin_activation_activate_check, check activation status and print
 * return 1 if system is under activated status or on trial and set result with NO_ERROR, or 0 if not and set result
 */
int kylin_activation_activate_check(int *result)
{
	int under_activation = 0;
	int on_trial = 0;
	int has_old_activation = 0;
	struct tm* old_expire = NULL;
	struct tm* tm_trial = NULL;
	int expired = 1;
	//int diff = INT_MAX;
	char buf[BUF_SIZE];
	char* p = NULL;
	int ret = -1;
	char *message = NULL;

	ret = kylin_activation_validation_check();
	if (ret != NO_ERROR)
	{
		_set_error_code(result, ret);

		message = kylin_activation_get_result_message(ret);
		if (message)
		{
			log_write(LOG_FILE, message, "II", 1);
		}
		return NOT_ACTIVATED;
	}

	if (license_should_escape())
	{
		_set_error_code(result, NO_ERROR);
		printf("系统已经激活\n");
		return 1;
	}

	under_activation = kylin_activation_activate_status(result);


	if(string_valid(info.license_trial))
	{
		if(_kylin_activation_trial_status())
		{
			//printf("系统在试用期内。\n");
			// printf(_("In trial period.\n"));
			if (*result == NO_SERIAL_NUMBER_ERROR || *result == SERIAL_NUMBER_VALIDATION_ERROR)
			{
				log_write(LOG_FILE, "系统未被激活，系统在试用期内", "WW", 1);
			}
			on_trial = 1;
		}
		else
		{
			//printf("系统已过试用期。\n");
			// printf(_("Trial period is expired.\n"));
			if (*result == NO_SERIAL_NUMBER_ERROR || *result == SERIAL_NUMBER_VALIDATION_ERROR)
			{
				log_write(LOG_FILE, "系统未被激活，系统已过试用期", "EE", 1);
			}
		}

		//printf("试用期到期时间: %s\n", license_trial);
		printf(_("Expiration date of trial: %s\n"), info.license_trial);
	}

	if(string_valid(info.old_expire_date))
	{
		old_expire = date_string_to_tm(string_address(info.old_expire_date));
		if(old_expire)
		{
			has_old_activation = 1;

			expired = date_expired(old_expire);
			if(!expired && expired != INT_MAX)
			{
				//printf("系统已激活\n");
				printf(_("System is activated.\n"));

				//diff = date_diff_expiration(old_expire);
				//if(diff >= -90 && diff != INT_MAX)
					//printf(_("System activation will expire in %d days.\n"), 0 - diff);
					//printf("系统激活将在%d天后到期\n", 0 - diff);
			}
			else
			{
				//printf("系统已激活\n");
				printf(_("System is activated.\n"));
			}
			//printf("技术服务到期时间： %s \n", old_expire_date_str);
			printf(_("Expiration date of technical service: %s \n"), info.old_expire_date);
		}
		else
			printf(_("System is not activated.\n"));
			//printf("系统未被激活\n");

	}
	else
		printf(_("System is not activated.\n"));
		//printf("系统未被激活\n");

	if(string_valid(info.license_trial))
	{
		tm_trial = date_string_to_tm(string_address(info.license_trial));
	}

	if(old_expire)
	{
		memset(buf, 0, BUF_SIZE);
		sprintf(buf, "%4d-%02d-%02d",
			old_expire->tm_year + 1900,
			old_expire->tm_mon + 1,
			old_expire->tm_mday);

		kylin_activation_kyinfo_set_value(info_file, "os", "term", buf);
	}

//	if(0 != access(RESULT_INTERFACE, F_OK))
//	{
//		/* this can be a old kernel */
//		if(under_activation || on_trial || has_old_activation)
//		{
//			kylin_activation_verify_contact();
//		}
//	}
//	else
//	{
//		/* for the new kernel */
//		if(under_activation || on_trial)
//		{
//			kylin_activation_verify_contact();
//		}
//	}

	// now for the new authorization rules
	if (under_activation || on_trial || has_old_activation)
		kylin_activation_verify_contact();

	if(old_expire)
		free(old_expire);
	if(tm_trial)
		free(tm_trial);

	if(*result != NO_ERROR)
		return 0;
		
	if((p = getenv("KYLIN_REALLY_ACTIVATED")) && (strncmp(p, "y", 1) == 0))
		return under_activation;
	else
		return (under_activation || on_trial || has_old_activation);
}


/*
 * kylin_activation_get_expire_date, get expire date string
 * return expire date string if succeed and set result with NO_ERROR, or NULL if not and set result
 */
char* kylin_activation_get_expire_date(int* result)
{
	int ret;

	if (license_should_escape())
	{
		_set_error_code(result, NO_ERROR);
		return strdup(escape_get_expire_date());
	}

	ret = kylin_activation_validation_check();
	if(ret != NO_ERROR)
	{

		_set_error_code(result, ret);
		return NULL;
	}

	ret = _kylin_activation_activate_status(string_address(info.real_serial), result, 0);

	if(*result != NO_ERROR)
		return NULL;

	if(!ret)
		return NULL;

	return (string_valid(info.activate_file_date) ? strdup(info.activate_file_date) : NULL);
}

/*
 * kylin_activation_get_expire_date, get old expire date string, no matter whether system is under activated status
 * return expire date string if succeed and set result with NO_ERROR, or NULL if not and set result
 */
char* kylin_activation_get_old_expire_date(int* result)
{
	int ret = -1;

	ret = kylin_activation_validation_check();
	if(ret != NO_ERROR)
	{

		_set_error_code(result, ret);
		return NULL;
	}
	else{
		if (license_should_escape())
		{
			_set_error_code(result, NO_ERROR);
			return strdup(escape_get_expire_date());
		}
	}

	_kylin_activation_activate_status(string_address(info.real_serial), result, 0);

	if(*result != NO_ERROR)
		return NULL;

	return (string_valid(info.old_expire_date) ? strdup(info.old_expire_date) : NULL);
}

/*
 * _kylin_activation_activate_system, activate system
 * return NO_ERROR if succeed, or error number if not
 */
int _kylin_activation_activate_system(const char* activation_code_with_hyphen, const char* ukey_hid, const char* serial_no, int prompt)
{
	return _kylin_activation_activate_system_real(activation_code_with_hyphen, ukey_hid, serial_no, prompt, 0);
}

/*
 * _kylin_activation_activate_system_test, test if activation can succeed
 * return NO_ERROR if succeed, or error number if not
 */
int _kylin_activation_activate_system_test(const char* activation_code_with_hyphen, const char* ukey_hid, const char* serial_no)
{
	return _kylin_activation_activate_system_real(activation_code_with_hyphen, ukey_hid, serial_no, 0, 1);
}

/*
 * _kylin_activation_activate_system_real, activate system really , not just test
 * return NO_ERROR if succeed, or error number if not
 */
static int _kylin_activation_activate_system_real(const char* activation_code_with_hyphen, const char* ukey_hid, const char* serial_no, int prompt, int test)
{
	char* activation_code = NULL;
	int ret = -1;
	char* hw_info = NULL;
	struct tm *expire_date = NULL; // 激活码所含到期日期
	struct tm *old_expire_date = NULL; // 本身已存在激活码的到期日期
	struct tm *trial_expire_date = NULL; // LICENSE文件中的试用期到期日期
	char* old_act_code = NULL;
	//int code_has_expired = 1;
	char buf[BUF_SIZE];
	char* register_code = NULL;
	char* register_code_old = NULL;
	int license_serial_mode = SERIAL_MODE_UNKNOWN;
	int serial_mode = SERIAL_MODE_UNKNOWN;

	uid = getpid();
	if(!serial_no)
	{
		return NO_SERIAL_NUMBER_ERROR;
	}

	if(!_serial_validation_check(serial_no))
	{
		return SERIAL_NUMBER_VALIDATION_ERROR;
	}

	// check serial_no first
	serial_mode = _serial_number_mode(serial_no);
	if((SERIAL_MODE_UNKNOWN == serial_mode) || (SERIAL_MODE_BATCH == serial_mode))
	{
		return SERIAL_NUMBER_VALIDATION_ERROR;
	}
	if(SERIAL_MODE_LEGACY == serial_mode)
	{
		if(strcmp(info.license_serial, serial_no) != 0)
		{
			return ACTIVATION_SERIAL_NUMBER_MATCH_ERROR;
		}
	}

	// check match
	license_serial_mode = _serial_number_mode(string_address(info.license_serial));
	if((SERIAL_MODE_LEGACY == license_serial_mode) || (SERIAL_MODE_NEW == license_serial_mode))
	{
		if(strcmp(info.license_serial, serial_no) != 0)
		{
			return ACTIVATION_SERIAL_NUMBER_MATCH_ERROR;
		}
	} else if(SERIAL_MODE_BATCH == license_serial_mode) {
		if(!_product_type_check(string_address(info.license_serial), serial_no))
		{
			return PRODUCT_TYPE_MATCH_ERROR;
		}
	} else {
		return LICENSE_SERIAL_NUMBER_VALIDATION_ERROR;
	}


	activation_code = code_remove_hyphen(activation_code_with_hyphen);
	if(!activation_code)
		return ACT_CODE_DEAL_HYPHEN_ERROR;

	hw_info = hardware_id_save_kyhwid();
	if(!hw_info)
	{
		ret = HARDWARE_INFORMATION_ERROR;
		goto activate_out;
	}

	register_code = encrypted_number_generate_register(hw_info, serial_no, "");
	// fprintf(stderr,"Register code:%s\n",register_code);
	syslog(LOG_INFO,"[%d]: Register code:%s",uid,register_code);
	if(!register_code)
	{
		ret =  REGISTER_CREATION_ERROR;
		goto activate_out;
	}

	if( (!activate_number_validate_normal(hw_info, serial_no, activation_code) ||
		((expire_date = activation_expire_date_normal(hw_info, serial_no, activation_code)) == NULL)) && 
	    (!activate_number_validate_ukey(register_code, ukey_hid, activation_code) || 
		((expire_date = activation_expire_date_ukey(register_code, ukey_hid, activation_code)) == NULL)) )
	{
		ret = INVALID_ACT_CODE;
		goto activate_out;
	}

    /*
	code_has_expired = date_expired(expire_date);
	if(code_has_expired)
	{
		ret = ACT_CODE_HAS_EXPIRED;
		goto activate_out;
	}
    */

	if(string_valid(info.license_trial))
		trial_expire_date = date_string_to_tm(string_address(info.license_trial));
	if(trial_expire_date)
	{
        /*
		if(date_is_newer(trial_expire_date, expire_date))
		{
			ret =  ACT_EXPIRE_EARLIER_THAN_TRIAL;
			goto activate_out;
		}
        */
	}

	old_act_code = activation_code_load(activate_file);
	if(old_act_code)
	{
		old_expire_date = activation_expire_date_normal(hw_info, string_address(info.real_serial), old_act_code);
		if(!old_expire_date)
		{
			register_code_old = encrypted_number_generate_register(hw_info, string_address(info.real_serial), "");
			if (register_code_old)
			{
				old_expire_date = activation_expire_date_ukey(register_code_old, string_address(info.kyinfo_ukey), old_act_code);
			}
		}
	}

	if(old_expire_date)
	{
		if(date_is_newer(old_expire_date, expire_date))
		{
			memset(buf, 0, BUF_SIZE);
			sprintf(buf, "%4d-%02d-%02d", 
				old_expire_date->tm_year + 1900, 
				old_expire_date->tm_mon + 1, 
				old_expire_date->tm_mday);

			bzero(info.activate_file_date, sizeof(info.activate_file_date));
			strcpy(info.activate_file_date, buf);

			ret = ACT_EXPIRE_EARLIER_THAN_ORIGINAL;
			goto activate_out;
		}
	}
	

	if(test)
	{
		if(activation_code_save(activate_file, register_code))
			ret = NO_ERROR;
		else
			ret = ACT_CODE_SAVE_ERROR;

		goto activate_out;
	}


	if(activation_code_save(activate_file, activation_code))
	{
		char term[BUF_SIZE];

		memset(term, 0, BUF_SIZE);
		sprintf(term, "%4d-%02d-%02d", expire_date->tm_year + 1900,
			expire_date->tm_mon + 1, expire_date->tm_mday);
		kylin_activation_kyinfo_set_value(info_file, "os", "term", term);

		if(serial_no && strlen(serial_no) > 0)
		{
			kylin_activation_kyinfo_set_value(info_file, "servicekey", "key", serial_no);
		}

		bzero(info.real_serial, sizeof(info.real_serial));
		strcpy(info.real_serial, serial_no);

		ret = NO_ERROR;
	}
	else
	{
		ret = ACT_CODE_SAVE_ERROR;
	}

	if(ret == NO_ERROR)
	{
		memset(buf, 0, BUF_SIZE);

		sprintf(buf, "%4d-%02d-%02d", 
			expire_date->tm_year + 1900, 
			expire_date->tm_mon + 1, 
			expire_date->tm_mday);

		if(prompt)
		{
			//printf("激活成功\n");
			//printf("到期时间为： %s\n", buf);
			// printf(_("System is activated.\n"));
			// printf(_("Expiration date: %s\n"), buf);
			syslog(LOG_INFO,"[%d]: System is activated.",uid);
			syslog(LOG_INFO,"[%d]: Expiration date: %s",uid,buf);
		}

		kylin_activation_verify_contact();

		kylin_activation_kyinfo_set_value(info_file, "os", "term", buf);

		bzero(info.activate_file_date, sizeof(info.activate_file_date));
		strcpy(info.activate_file_date, buf);
		log_write(LOG_FILE, "系统已经激活", "II", 1);
	}


activate_out:

	if(register_code)
		free(register_code);
	if(hw_info)
		free(hw_info);
	if(old_act_code)
		free(old_act_code);
	if(old_expire_date)
		free(old_expire_date);
	if(activation_code)
		free(activation_code);
	if(expire_date)
		free(expire_date);
	if(trial_expire_date)
		free(trial_expire_date);
	if(register_code_old)
		free(register_code_old);

	return ret;

}

/*
 * _update_kyinfo_ukey, update kyinfo_ukey value
 */
static void _update_kyinfo_ukey(const char* kyinfo_file)
{
	GKeyFile* tmp_keyfile_kyinfo = NULL;
	char* _kyinfo_ukey = NULL;

	tmp_keyfile_kyinfo = key_file_load_from_file(kyinfo_file);
	if(!tmp_keyfile_kyinfo)
	{
		bzero(info.kyinfo_ukey, sizeof(info.kyinfo_ukey));
	} else {
		_kyinfo_ukey = key_file_get_value(tmp_keyfile_kyinfo, "servicekey", "ukey");

		if(_kyinfo_ukey && (0 == strcmp(_kyinfo_ukey, "None")))
			_kyinfo_ukey = NULL;
		if(_kyinfo_ukey)
		{
			bzero(info.kyinfo_ukey, sizeof(info.kyinfo_ukey));
			strcpy(info.kyinfo_ukey, _kyinfo_ukey);
		}

		g_key_file_free(tmp_keyfile_kyinfo);
	}
}

/*
 * kylin_activation_activate_system, activate system with activation code
 * return NO_ERROR if succeed, or error number if not
 */
int kylin_activation_activate_system(const char* activation_code_with_hyphen)
{
	int ret = -1;
	ret = kylin_activation_validation_check();
	if(ret != NO_ERROR)
		return ret;

	return kylin_activation_activate_system_with_serial(string_address(info.real_serial), activation_code_with_hyphen);
}

/*
 * kylin_activation_activate_system_with_serial, activate system with activation code
 * return NO_ERROR if succeed, or error number if not
 */
int kylin_activation_activate_system_with_serial(const char* serial_no, const char* activation_code_with_hyphen)
{
	int ret = -1;
	int result = -1;
	char* ukey_hid = NULL;
	int activated = 0;
	char* old_activation_code = NULL;


	ret = kylin_activation_validation_check();
	if(ret != NO_ERROR)
		return ret;

	if(activation_code_with_hyphen && (0 != strlen(activation_code_with_hyphen)))
		return _kylin_activation_activate_system(activation_code_with_hyphen, string_address(info.kyinfo_ukey), serial_no, 1);

	//fprintf(stderr, "请稍候\n");
	fprintf(stderr, _("Wait for a moment please...\n"));

	activated = _kylin_activation_activate_status(string_address(info.real_serial), &result, 0);
	if(result != NO_ERROR)
	{
		if(result != NO_SERIAL_NUMBER_ERROR)
		{
			ret =  result;
			goto activate_system_out;
		}
	}

	old_activation_code = activation_code_load(activate_file);

	if(NO_ACTIVATED_CODE == activation_status)
		ret = ukey_activate_system(info.license_serial, NULL, NULL);
	else if(NORMALLY_ACTIVATED == activation_status)
		ret = ukey_activate_system(info.license_serial, NULL, string_address(info.old_expire_date));
	else if(WITH_UKEY_ACTIVATED == activation_status)
		ret = ukey_activate_system(info.license_serial, string_address(info.kyinfo_ukey), string_address(info.old_expire_date));
	else
		ret = OTHER_ERROR;

	if(ret == NO_ERROR)
	{
		ukey_hid = ukey_get_hid();

		if(ukey_hid)
		{
			kylin_activation_kyinfo_set_value(info_file, "servicekey", "ukey", ukey_hid);
			free(ukey_hid);
		}

		_update_kyinfo_ukey(KYLIN_INFORMATION_FILE);

		activated = _kylin_activation_activate_status(string_address(info.real_serial), &result, 0);
		if(result != NO_ERROR)
		{
			ret = result;
			goto activate_system_out;
		}

		if(string_valid(info.old_expire_date))
		{
			printf(_("System is activated.\n"));
			printf(_("Expiration date: %s\n"), info.old_expire_date);
			kylin_activation_verify_contact();
		}
	}

	if(NO_ERROR != ret)
	{
		if(old_activation_code)
			activation_code_save(activate_file, old_activation_code);
		else
			remove(activate_file);
	}

activate_system_out:
	(void)activated;

	return ret;
}

/*
 * log_write, write log to /var/log/kylin-activation-check
 */
void log_write(const char* log_file, const char* message, const char* type, int log)
{
	int fd;
	char buf[BUF_SIZE];
	char time_buf[BUF_SIZE];
	char* time_str = NULL;
	time_t timep;
	struct tm *t = NULL;
    int ret;

	char* format = "%Y-%m-%d %H:%M:%S";

	if(!log)
		return;

	fd = open(log_file, O_APPEND | O_CREAT | O_WRONLY, 00640);

	if(fd < 0)
		return ;

	memset(buf, 0, BUF_SIZE);
	memset(time_buf, 0, BUF_SIZE);

	time(&timep);
	t = localtime(&timep);

	strftime(time_buf, BUF_SIZE, format, t);

	time_str = strdup(time_buf);

	if(!time_str || (strlen(time_str) == 0))
		sprintf(buf, "(%s) %s\n", type, message);
	else
	{
		char* p;
		p = time_str;
		while(*p != '\0')
		{
			if(*p == '\n')
				*p = '\0';
			++p;
		}
		sprintf(buf, "(%s) Time: %s\t\tMessage: %s\n", type, time_str, message);
	}

	ret = write(fd, buf, strlen(buf));
    (void) ret;

	close(fd);

	if (time_str) {
		free(time_str);
		time_str = NULL;
	}
}


/*
 * contact_file_stat, check if contact file matches mode
 * return 1 if matches, or 0 if not
 */
static int contact_file_stat(const char* name, mode_t mode)
{
	
	return file_stat(name, mode);
}

/*
 * contact_file_read, read content of contact file
 */
static char* contact_file_read(const char* name)
{
	int fd;
	char* result = NULL;
	char buf[BUF_SIZE];
	int ret;

	memset(buf, 0, BUF_SIZE);

	fd = open(name, O_RDONLY);

	if(fd < 0)
		return NULL;

	ret = read(fd, buf, BUF_SIZE);

	if(ret < 0)
	{
		close(fd);
		return NULL;
	}


	result = (char*)malloc(ret + 1);
	if(!result)
	{
		close(fd);
		return NULL;
	}

	result[ret] = '\0';

	memcpy(result, buf, ret);
	close(fd);

	return result;
}

/*
 * contact_file_write, write data to contact file
 */
static void contact_file_write(const char* name, const char* data, size_t length)
{
	int fd;
    int ret;

	fd = open(name, O_WRONLY);

	if(fd < 0)
		return;

	ret = write(fd, data, length);
    (void) ret;

	close(fd);
}

/*
 * digest_generate, generate digest string for string whole
 */
static char* digest_generate(const char* whole)
{
	unsigned char md[SHA_DIGEST_LENGTH];
	char buf_str[2 * SHA_DIGEST_LENGTH];
	char* digest = NULL;

	int i;

	SHA_CTX ctx;

	SHA1_Init(&ctx);
	SHA1_Update(&ctx, whole, strlen(whole));
	SHA1_Final(md, &ctx);

	for(i = 0; i < SHA_DIGEST_LENGTH; ++i)
		sprintf(&buf_str[2 * i], "%02x", md[i] & 0xff);

	digest = (char*)malloc(2 * SHA_DIGEST_LENGTH + 1);
	if(!digest)
		return NULL;

	digest[2 * SHA_DIGEST_LENGTH] = '\0';

	memcpy(digest, buf_str, 2 * SHA_DIGEST_LENGTH);

	return digest;
	
}

/*
 * contact_file_process, contact kernel with contact file
 */
static void contact_file_process(const char* file_name, const char* rand_str)
{
	char* whole_str = NULL;
	char* digest = NULL;

	whole_str = g_strconcat(rand_str, "kylin", NULL);
	if(!whole_str)
		return;


	digest = digest_generate(whole_str);
	
	g_free(whole_str);

	if(!digest || (strlen(digest) != 2 * SHA_DIGEST_LENGTH))
		goto out;
	if(contact_file_stat(file_name, S_IWUSR))
		contact_file_write(file_name, digest, strlen(digest));

out:
	if (digest) {
		free(digest);
		digest = NULL;
	}
	return;
}

/*
 * kylin_activation_verify_contact, contact to kernel to tell if system verification status
 */
static void kylin_activation_verify_contact()
{
	char* read_file = NULL;
	char* write_file = NULL;

	read_file = g_strconcat("/", "sys", "/", "kylin", "_", "authentication", "/", "ret", NULL);
	write_file = g_strconcat("/", "sys", "/", "kylin", "_", "authentication", "/", "result", NULL);

	kylin_activation_contact(read_file, write_file);

#ifndef CHECK_ENV
	kylin_activation_contact(read_file, read_file);
#endif

	// for the old kernel
	if(0 != access(RESULT_INTERFACE, F_OK))
		kylin_activation_contact(read_file, read_file);

	if(read_file)
		g_free(read_file);
	if(write_file)
		g_free(write_file);
}

#ifdef CHECK_ENV
/*
 * kylin_activation_env_contact, contact to kernel to tell if system environment  status
 */
static void kylin_activation_env_contact()
{
	char* communicate_file = NULL;

	communicate_file = g_strconcat("/", "sys", "/", "kylin", "_", "authentication", "/", "ret", NULL);

	kylin_activation_contact(communicate_file, communicate_file);

	if(communicate_file)
		g_free(communicate_file);
}
#endif

/*
 * kylin_activation_contact, contact to file to read and write verify message
 */
static void kylin_activation_contact(const char* read_file, const char* write_file)
{
	char* rand_str = NULL;

	if(contact_file_stat(read_file, S_IRUSR))
		rand_str = contact_file_read(read_file);

	if((NULL != rand_str) && (strlen(rand_str) == 4))
		contact_file_process(write_file, rand_str);

	if(rand_str) {
		free(rand_str);
		rand_str = NULL;
	}
}


/*
 * kylin_activation_status_check, get activation status
 * return 1 if under activated status, on trial or has ever been activated,
 * or 0 if not
 */
int kylin_activation_status_check(int *result)
{
	int ret;
	char* old_date = NULL;

	ret = kylin_activation_trial_status(result);
	if(ret)
		return 1;

	ret = kylin_activation_activate_status(result);
	if(ret)
		return 1;

	old_date = kylin_activation_get_old_expire_date(result);
	if(old_date) {
		free(old_date);
		old_date = NULL;
		return 1;
	}

	return 0;
}

/*
 * get_machine_info_from_sysfs, get machine information from system file.
 */ 
char* get_machine_info_from_sysfs(char* file_name)
{
	FILE * fp = NULL;
	char buf[BUF_SIZE];
	int i;

	fp = fopen(file_name, "r");
	if(!fp)
		return NULL;

	memset(buf, 0, BUF_SIZE);

	if(!fgets(buf, BUF_SIZE, fp))
	{
		fclose(fp);
		return NULL;
	}

	for(i = 0; i < BUF_SIZE; i++)
	{
		if((buf[i] == '\n') || (buf[i] == '\r'))
			buf[i] = '\0';
	}
	buf[BUF_SIZE - 1] = '\0';

	fclose(fp);

	return strdup(buf);
}

/*
 * get_machine_info_from_dmidecode, get machine information from dmidecode.
 */ 
char* get_machine_info_from_dmidecode(char* cmd)
{
	FILE* fp;
	char buf[BUF_SIZE];
	int i;

	if(access("/usr/sbin/dmidecode", F_OK | R_OK | X_OK) != 0)
		return NULL;

	fp = popen(cmd, "r");
	if(!fp)
		return NULL;

	memset(buf, 0, BUF_SIZE);
	if(!fgets(buf, BUF_SIZE, fp))
	{
		pclose(fp);
		return NULL;
	}

	for(i = 0; i < BUF_SIZE; i++)
	{
		if((buf[i] == '\n') || (buf[i] == '\r'))
			buf[i] = '\0';
	}
	buf[BUF_SIZE - 1] = '\0';

	pclose(fp);

	return strdup(buf);
}

char* kylin_activation_get_service_tag()
{
	if (0 == kylin_activation_check_oem())
	{
		int result = -1;
		char *encryptedServiceTag = kylin_activation_get_encrypted_hardware_info(&result);
		return encryptedServiceTag;
	}
	else
	{
		char *service_tag = NULL;
		service_tag = get_machine_info_from_sysfs("/sys/class/dmi/id/product_serial");
		if (service_tag)
			return service_tag;

		service_tag = get_machine_info_from_dmidecode("/usr/sbin/dmidecode -t 1 |grep -i 'Serial Number' |awk '{print $3}'");
		return service_tag;
	}
	return NULL;
}

char* kylin_activation_get_vendor()
{
	char *vendor = NULL;
	vendor = get_machine_info_from_sysfs("/sys/class/dmi/id/sys_vendor");
	if (vendor)
		return vendor;

	vendor = get_machine_info_from_dmidecode("/usr/sbin/dmidecode -t 1 |grep -i 'Family' |awk '{print $2}'");
	return vendor;
}

char* kylin_activation_get_model()
{
	char* model=NULL;
	model=get_machine_info_from_sysfs("/sys/class/dmi/id/product_sku");
	if(model)
	return model;

	model=get_machine_info_from_dmidecode("/usr/sbin/dmidecode -t 1 |grep -i 'Version' |awk '{print $2}'");
	return model;
}

int kylin_activation_check_oem()
{
	int ret=-1;
    char buf[256]={0};
    FILE *fp=fopen("/etc/LICENSE", "r");
    if(NULL!=fp)
    {
        while (NULL!=fgets(buf,256,fp))
        {
            if(strlen(buf)>6)
            {
                if(0==strncmp(buf,"METHOD",6))
                {
                    if(NULL!=strstr(buf,"oem"))
                    {
                        ret=0;
                        break;
                    }
                }
            }
        }
        fclose(fp);
    }
	return ret;
}

int kylin_activation_license_check(const char* l_file, const char* i_file)
{
	int result = -1;

	if(access(l_file,F_OK) != 0 || access(i_file,F_OK) != 0)
	{
		result = LICENSE_DETECTION_FAIL;
		goto _validation_out;
	}

	result=_kylin_activation_check_platform(l_file);
	if( result != NO_ERROR)
	{
		goto _validation_out;
	}

	if (_kylin_activation_system_os_check(l_file, i_file) != NO_ERROR)
	{
		result = SYSTEM_VERSION_INFORMATION_MATCH_ERROR;
		goto _validation_out;
	}

_validation_out:
	if(result != NO_ERROR)
	{
		return result;
	}

	return NO_ERROR;
}

char* kylin_activation_get_trial_date(int* result)
{
	int ret = -1;
	char*  trial_date= NULL;

	ret = kylin_activation_validation_check();
	if(ret != NO_ERROR)
	{

		_set_error_code(result, ret);
		return NULL;
	}

	if(string_valid(info.license_trial))
	{
		if(_kylin_activation_trial_status())
		{
			trial_date = strdup(info.license_trial);
		}
	}

	_set_error_code(result, NO_ERROR);
	return trial_date;
}

/*
 * kylin_activation_find_ukey, activate system with activation code
 * return NO_ERROR if succeed, or error number if not
 */
int kylin_activation_find_ukey(int* result)
{
	int iRet = NO_UKEY_FOUND;
	int iUkeyType = -1;

	iRet = ukey_usb_bus_find(&iUkeyType);
	_set_error_code(result, iRet);

	return iRet;
}

#if 0

int main(int argc, char** argv)
{
	//char *serial_no, *register_code, *qrcode = NULL;
	//int ret = -1;
	printf("%d\n", kylin_activation_activate_system(argv[1]));

	return 0;
}
#endif
